# -*- coding: utf-8 -*-
from typing import Optional
from zinx.utils.globalobj import GlobalObject, GlobalGevents
from zinx.ziface.iconnection import IConnection
from zinx.ziface.irouter import IRouter
from zinx.ziface.iserver import IServer
from zinx.ziface.imsghandler import IMsgHandler
from zinx.ziface.iconmanager import IConManager
from zinx.znet.connection import NewConnection
from zinx.znet.msghandler import NewMsgHandler
from zinx.znet.conmanager import NewConnManager
from gevent import monkey
import time
import socket
import gevent
import signal
import sys


# 把内置阻塞的库替换成非阻塞的socket
monkey.patch_socket()


class Server(IServer):
    def __init__(self, name: str, ip: str, port: int,
                 family: socket.AddressFamily = socket.AF_INET,
                 socket_kind: socket.SocketKind = socket.SOCK_STREAM):
        self.name: str = name
        self.family: socket.AddressFamily = family
        self.socket_kind: socket.SocketKind = socket_kind
        self.ip: str = ip
        self.port: int = port
        # self.Router: Optional[IRouter] = None
        self.msgHandler: IMsgHandler = NewMsgHandler()
        self.connManager: IConManager = NewConnManager()
        self.OnConnStart = None     # 函数类型  钩子函数
        self.OnConnStop = None      # 函数类型  钩子函数

    def Start(self):
        """
        启动服务器方法
        :return:
        """
        print("[启动] 服务监听，IP地址：%s, 端口：%s，已经启动\n" % (self.ip, self.port))
        self.msgHandler.StartWorkerPool()
        g1 = gevent.spawn(self.InitTCP)
        GlobalGevents.append(g1)

    def InitTCP(self):
        """
        初始化TCP链接
        :return:
        """
        # 1.获取一个TCP的Addr
        with socket.socket(self.family, self.socket_kind) as tcp:
            # 2.监听服务器的地址
            tcp.bind((self.ip, self.port))
            tcp.listen(128)
            print("[启动] %s服务启动成功，监听中......" % self.name)
            # 3.阻塞的等待客户端链接，处理客户端链接业务（读写）。
            cid: int = 0
            while True:
                print("开启接收")
                remote_socket, remote_addr = tcp.accept()
                if self.connManager.Len() >= GlobalObject.MaxConn:
                    remote_socket.close()
                    continue
                dealConn = NewConnection(self, remote_socket, cid, remote_addr, self.msgHandler)
                cid += 1
                g2 = gevent.spawn(dealConn.Start())
                GlobalGevents.append(g2)

    def Stop(self):
        """
        停止服务器方法
        :return:
        """
        print("服务停止")
        # 断开所有链接，回收
        self.connManager.ClearConn()

    def Serve(self):
        """
        开启业务服务方法
        :return:
        """
        self.Start()
        gevent.joinall(GlobalGevents)
        # 阻塞一下
        while True:
            time.sleep(10)

    def AddRouter(self, msgID: int, router: IRouter):
        """
        添加路由
        :param msgID:
        :param router:
        :return:
        """
        self.msgHandler.AddRouter(msgID, router)
        print("添加路由成功")

    def GetConnMgr(self) -> IConManager:
        """
        得到链接管理
        :return:
        """
        return self.connManager

    def SetOnConnStart(self, cb):
        """
        设置该Server的连接创建时Hook函数
        :param cb: 函数类型
        :return:
        """
        self.OnConnStart = cb

    def SetOnConnStop(self, cb):
        """
        设置该Server的连接断开时的Hook函数
        :param cb:函数类型
        :return:
        """
        self.OnConnStop = cb

    def CallOnConnStart(self, conn: IConnection):
        """
        调用连接OnConnStart Hook函数
        :param conn:
        :return:
        """
        if self.OnConnStart:
            print("---> CallOnConnStart....")
            self.OnConnStart(conn)

    def CallOnConnStop(self, conn: IConnection):
        """
        调用连接OnConnStop Hook函数
        :param conn:
        :return:
        """
        if self.OnConnStop:
            print("---> CallOnConnStart....")
            self.OnConnStop(conn)

# def CallBackToClient(conn: socket.socket, data: bytes):
#     print("回显功能")
#     try:
#         conn.send(data)
#     except Exception as e:
#         print(e)
#         raise Exception("回显功能异常")


# 创建一个全局的server
m_server: Optional[IServer] = None


# 获取server
def NewServer() -> IServer:
    global m_server
    if m_server:
        return m_server
    m_server = Server(GlobalObject.Name, GlobalObject.Host, GlobalObject.TcpPort)
    GlobalObject.SetTcpServer(m_server)
    return m_server


# 接收停止信号，要不然报错看着烦
def signal_handler(signal, frame):
    global m_server
    m_server.Stop()
    print("程序已退出")
    sys.exit(0)


# 接收停止信号 ctrl+c
signal.signal(signal.SIGINT, signal_handler)
